﻿using Red.Controls.Diagrams.Declarators;
using System;

namespace Red.Controls.Diagrams.ViewModels
{
    /// <summary>
    /// Factory to create ViewModel for each node. It depends on node GraphBlockShape enum.
    /// </summary>
    public static class NodeViewModelFactory
    {
        #region Public methods

        public static NodeViewModel CreateNodeViewModel( NodeDeclarators declarators, NodeDeclarator nodeDeclarator, IObject iObject, bool centerNode = false )
        {
            var node = CreateNodeViewModelInternal( declarators, nodeDeclarator, iObject );
            if ( centerNode )
                AttachEvents( node );

            return node;
        }

        #endregion Public methods

        #region Private methods

        private static void AttachEvents( NodeViewModel node )
        {
            // 
            // We want to center the node.
            //
            // For this to happen we need to wait until the UI has determined the 
            // size based on the node's data-template.
            //
            // So we define an anonymous method to handle the SizeChanged event for a node.
            //
            // Note: If you don't declare sizeChangedEventHandler before initializing it you will get
            //       an error when you try and unsubscribe the event from within the event handler.
            //
            EventHandler<EventArgs> sizeChangedEventHandler = null;
            sizeChangedEventHandler =
                delegate
                {
                    //
                    // This event handler will be called after the size of the node has been determined.
                    // So we can now use the size of the node to modify its position.
                    //
                    node.X -= node.Size.Width / 2;
                    node.Y -= node.Size.Height / 2;

                    //
                    // Don't forget to unhook the event, after the initial centering of the node
                    // we don't need to be notified again of any size changes.
                    //
                    node.SizeChanged -= sizeChangedEventHandler;
                };

            //
            // Now we hook the SizeChanged event so the anonymous method is called later
            // when the size of the node has actually been determined.
            //
            node.SizeChanged += sizeChangedEventHandler;
        }

        /// <summary>
        /// Creates NodeViewModel object based on raw data from IObject and visual settings from NodeDeclarator. It also creates it's connectors.
        /// </summary>
        /// <param name="declarators">All node declarators.</param>
        /// <param name="nodeDeclarator">Contains visual setting of this node. Used to provide automatic connector coloring based on property types.</param>
        /// <param name="iObject">Contains data that can be edited later by users (position of the node, comment, properties).</param>
        /// <returns>New NodeViewModel object.</returns>
        private static NodeViewModel CreateNodeViewModelInternal( NodeDeclarators declarators, NodeDeclarator nodeDeclarator, IObject iObject )
        {
            var nodeViewModel = new NodeViewModel( iObject, declarators );
            nodeViewModel.InitFromNodeDeclarator( nodeDeclarator );

            return nodeViewModel;
        }

        #endregion Private methods
    }
}
